/**
 * 
 */
package com.pub.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Stack;

import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * @author ivan ling
 *
 */
public class HTMLUtils extends ConstantUtils
{

	/**
	 * 
	 */
	public HTMLUtils() 
	{
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) 
	{
		
	}

	/** system print dom tree
	 * @param node # current node
	 */
	public static void printDOMTree(Node node) 
	{ 
		int type = node.getNodeType();
		
		switch (type) { 
		  // print the document element 
			case Node.DOCUMENT_NODE: { 
				NodeList children = node.getChildNodes(); 
				if (children != null) { 
					int len = children.getLength(); 
					for (int i = 0; i < len; i++) 
						printDOMTree(children.item(i)); 
				} 

				break; 
			} 

			// print element with attributes 
			case Node.ELEMENT_NODE: { 
				System.out.print("<"); 
				System.out.print(node.getNodeName()); 
				NamedNodeMap attrs = node.getAttributes(); 
				if(attrs != null){
					for (int i = 0; i < attrs.getLength(); i++) { 
						Node attr = attrs.item(i); 
						System.out.print(" " + attr.getNodeName() + "=\"" + attr.getNodeValue() + "\""); 
					}
				}
				System.out.println(">"); 

				NodeList children = node.getChildNodes(); 
				if (children != null) { 
					int len = children.getLength(); 
					for (int i = 0; i < len; i++) 
						printDOMTree(children.item(i)); 
				} 

				break; 
			} 

		   // handle entity reference nodes 
			case Node.ENTITY_REFERENCE_NODE: { 
				System.out.print("&"); 
				System.out.print(node.getNodeName()); 
				System.out.print(";"); 
				break; 
			} 

		   // print cdata sections 
			case Node.CDATA_SECTION_NODE: { 
				System.out.print("<![CDATA["); 
				System.out.print(node.getNodeValue()); 
				System.out.print("]]>"); 
				break; 
			} 

		   // print text 
			case Node.TEXT_NODE: { 
				System.out.print(node.getNodeValue()); 
				break; 
			} 

		   // print processing instruction 
			case Node.PROCESSING_INSTRUCTION_NODE: { 
				System.out.print("<?"); 
				System.out.print(node.getNodeName()); 
				String data = node.getNodeValue(); 
				{ 
					System.out.print(" "); 
					System.out.print(data); 
				} 
				System.out.print("?>"); 
				break; 
			} 
		 } 

	  	if (type == Node.ELEMENT_NODE) { 
	  		System.out.println(); 
	  		System.out.print("</"); 
	  		System.out.print(node.getNodeName()); 
	  		System.out.print(">"); 
	  	} 
	}

	/** get inner all html elements.
	 * @param node 			# current node
	 * @param sbReturnData 	# return all data.
	 * @param isContainSelf # contain current element self?
	 * @param strEnter 		# add enter char
	 */
	public static void getInnerHtml(Node node, StringBuilder sbReturnData, boolean isContainSelf, String strEnter) 
	{ 
		int type = node.getNodeType();
		
		switch (type) { 
		  // print the document element 
			case Node.DOCUMENT_NODE: { 
				NodeList children = node.getChildNodes(); 
				if (children != null) { 
					int len = children.getLength(); 
					for (int i = 0; i < len; i++) 
						getInnerHtml(children.item(i), sbReturnData, true, strEnter); 
				} 

				break; 
			} 

			// print element with attributes 
			case Node.ELEMENT_NODE: {
				StringBuilder sbCache = new StringBuilder(100);
				sbCache.append("<");
				sbCache.append(node.getNodeName());
				NamedNodeMap attrs = node.getAttributes(); 
				if(attrs != null){
					for (int i = 0; i < attrs.getLength(); i++) { 
						Node attr = attrs.item(i);
						sbCache.append(" ");
						sbCache.append(attr.getNodeName());
						sbCache.append("=\"");
						sbCache.append(attr.getNodeValue());
						sbCache.append("\"");
					}
				}
				
				sbCache.append(">");
				sbCache.append(strEnter);
				
				if(isContainSelf)
					sbReturnData.append(sbCache);
				
				NodeList children = node.getChildNodes(); 
				if (children != null) { 
					int len = children.getLength(); 
					for (int i = 0; i < len; i++) 
						getInnerHtml(children.item(i), sbReturnData, true, strEnter); 
				} 

				break; 
			} 
	   
			case Node.TEXT_NODE: {
				sbReturnData.append(node.getNodeValue());
				break; 
			} 
		 } 

	  	if (type == Node.ELEMENT_NODE) {
	  		StringBuilder sbCache = new StringBuilder(100);
	  		
	  		sbCache.append(strEnter);
	  		sbCache.append("</"); 
	  		sbCache.append(node.getNodeName()); 
	  		sbCache.append(">");
	  		
	  		if(isContainSelf)
	  			sbReturnData.append(sbCache);
	  	} 
	}
	
	/** get index dom tree
	 * 
	 * @param node  		# current node
	 * @param alNodeData 	# return string tree.
	 */ 
	public static void vdGetIndexTree(Node node, ArrayList<String> alNodeData) 
	{ 
		short type = node.getNodeType(); 
		switch (type) {
			case Node.ELEMENT_NODE: {
				if (node.getNodeName().equals("STYLE") || node.getNodeName().equals("SCRIPT"))
					return;
			  		
		  		String name = "<" + node.getNodeName(); 
		  		NamedNodeMap attrs = node.getAttributes(); 
		  		if (attrs != null) { 
		  			int length = attrs.getLength(); 
					for (int i = 0; i < length; i++) { 
						Node attr = attrs.item(i); 
						name += " " + attr.getNodeName(); 
						name += "=\"" + attr.getNodeValue() + "\""; 
					} 
		  		} 
		  		
		  		name += ">";
		  		
		  		alNodeData.add(name);

		  		NodeList children = node.getChildNodes(); 
		  		if (children != null) { 
		  			int length = children.getLength();
		  			for (int i = 0; i < length; i++){
		  				Node nd = children.item(i);
		  				if(nd.getNodeType() == Node.ELEMENT_NODE)
		  					vdGetIndexTree(nd, alNodeData);
		  				else if(nd.getNodeType() == Node.TEXT_NODE){
		  					if(nd.getNodeValue().trim().length() != 0)
		  						alNodeData.add(nd.getNodeValue());
		  				}
		  			}
		  		} 
		  		
		  		alNodeData.add("</" + node.getNodeName() + ">");
		  		
		  		break;
			} 
			case Node.TEXT_NODE: { 
				alNodeData.add(node.getNodeValue());
			  		
			  	break; 
			}
			  	
			case Node.DOCUMENT_NODE: { 
				NodeList children = node.getChildNodes(); 
				if (children != null) { 
					int len = children.getLength(); 
					for (int i = 0; i < len; i++)
						vdGetIndexTree(children.item(i), alNodeData);
				} 

				break; 
			}
		}
	}

	/** get document object
	 *
	 * @param node 			# current node
	 * @param alNodeData	# return data
	 */ 
	public static void getDocObject(Node node, ArrayList<Node> alNodeData) 
	{ 
		short type = node.getNodeType(); 
		switch (type) {
			case Node.ELEMENT_NODE: {
				if (node.getNodeName().equals("STYLE") || node.getNodeName().equals("SCRIPT"))
					return;
			  		
		  		String name = "<" + node.getNodeName(); 
		  		NamedNodeMap attrs = node.getAttributes(); 
		  		if (attrs != null) { 
		  			int length = attrs.getLength(); 
					for (int i = 0; i < length; i++) { 
						Node attr = attrs.item(i); 
						name += " " + attr.getNodeName(); 
						name += "=\"" + attr.getNodeValue() + "\""; 
					} 
		  		} 
		  		
		  		name += ">";
		  		
		  		alNodeData.add(node);

		  		NodeList children = node.getChildNodes(); 
		  		if (children != null) { 
		  			int length = children.getLength();
		  			for (int i = 0; i < length; i++){
		  				Node nd = children.item(i);
		  				if(nd.getNodeType() == Node.ELEMENT_NODE)
		  					getDocObject(nd, alNodeData);
		  				else if(nd.getNodeType() == Node.TEXT_NODE){
		  					if(nd.getNodeValue().trim().length() != 0)
		  						alNodeData.add(nd);
		  				}
		  			}
		  		} 
		  		
		  		alNodeData.add(node);
		  		
		  		break; 
			} 
			case Node.TEXT_NODE: { 
			  	alNodeData.add(node);
			  		
			  	break; 
			}
			case Node.DOCUMENT_NODE: { 
				NodeList children = node.getChildNodes(); 
				if (children != null) { 
					int len = children.getLength(); 
					for (int i = 0; i < len; i++)
						getDocObject(children.item(i), alNodeData);
				} 

				break; 
			}
		}
	}
		  
	/** get html document title.
	 * @param node # document node
	 */
	public static String getTitle(Node node) 
	{
		if (node.getNodeType() == Node.ELEMENT_NODE) {
			if ("title".equalsIgnoreCase(node.getNodeName())) {
				return node.getTextContent();
			}
		}
		
		NodeList children = node.getChildNodes();
		if (children != null) {
			int len = children.getLength();
			String strReturn;
			for (int i = 0; i < len; i++) {
				strReturn = getTitle(children.item(i));
				if (strReturn != null)
					return strReturn;
			}
		}
		
		return null;
	}
	
	/** get all text in node.
	 * @param sb 	# save all text of node
	 * @param node 	# current node.
	 */	
	public static void getText(StringBuffer sb, Node node) 
	{
		if (node.getNodeType() == Node.TEXT_NODE) {
			sb.append(node.getNodeValue());
		}
		NodeList children = node.getChildNodes();
		if ( children != null ) {
			int len = children.getLength();
			for ( int i = 0; i < len; i++ ) {
				getText(sb, children.item(i));
			}
		}
	}
	
	
	/** get all url between ndRoot node.
	 * @param noRoot content of node
	 */
	public static HashSet<String> getAllURL(Node ndRoot) 
	{
		HashSet<String> hsReturn = new HashSet<String>();
		Stack<Node> st = new Stack<Node>();
		st.push(ndRoot);
		
		int i, len;
		Node node;
		while(st.size() > 0){
			node = st.pop();
			if (node.getNodeType() == Node.ELEMENT_NODE) {
				if ("a".equalsIgnoreCase(node.getNodeName())) {
					NamedNodeMap nnm = node.getAttributes();
					
					hsReturn.add(nnm.getNamedItem("href").getTextContent());
				}
			}
			
			NodeList children = node.getChildNodes();
			if (children != null) {
				len = children.getLength();
				for (i = 0; i < len; i++) {
					st.push(children.item(i));
				}
			}
		}
			
		return hsReturn;
	}
	
	/** get all url between ndRoot node.
	 * @param noRoot content of node
	 */
	public static HashMap<String, String> getAllURL1(Node ndRoot) 
	{
		HashMap<String, String> hsReturn = new HashMap<String, String>();
		Stack<Node> st = new Stack<Node>();
		st.push(ndRoot);
		
		int i, len;
		Node node;
		while(st.size() > 0){
			node = st.pop();
			if (node.getNodeType() == Node.ELEMENT_NODE) {
				if ("a".equalsIgnoreCase(node.getNodeName())) {
					NamedNodeMap nnm = node.getAttributes();
					if(nnm.getNamedItem("href") != null)
						hsReturn.put(nnm.getNamedItem("href").getTextContent(), node.getTextContent());
				}
			}
			
			NodeList children = node.getChildNodes();
			if (children != null) {
				len = children.getLength();
				for (i = 0; i < len; i++) {
					st.push(children.item(i));
				}
			}
		}
			
		return hsReturn;
	}
	
	/** get custom content index between strStartTag and strEndTag
	 * 
	 * @param strSource
	 * @param strStartTag
	 * @param strEndTag
	 */
	public static String strGetCustomText(String strSource, String strStartTag, String strEndTag)
	{
		if(strSource == null || strSource.equals(""))
			return strSource;
		
		int iStart = 0, iEnd;
		if(strStartTag != null && !strStartTag.equals("")){
			iStart = strSource.indexOf(strStartTag);
			
			if(iStart == -1)
				iStart = 0;
			else
				iStart += strStartTag.length();
		}
		
		iEnd = strSource.indexOf(strEndTag, iStart);
		if(iEnd == -1)
			iEnd = strSource.length();
		
		return strSource.substring(iStart, iEnd);
	}
	
	/** get custom content index between strStartTag and strEndTag
	 * 
	 * @param strSource
	 * @param strStartTag
	 * @param strEndTag
	 */
	public static String strGetCustomLastText(String strSource, String strStartTag, String strEndTag)
	{
		if(strSource == null || strSource.equals(""))
			return strSource;
		
		int iStart = 0, iEnd;
		if(strStartTag != null && !strStartTag.equals("")){
			iStart = strSource.indexOf(strStartTag);
			
			if(iStart == -1)
				iStart = 0;
			else
				iStart += strStartTag.length();
		}
		
		System.out.println("istart = " + iStart);
		iEnd = strSource.lastIndexOf(strEndTag);
		System.out.println("iendb = " + iEnd);
				
		if(iEnd == -1)
			iEnd = strSource.length();
		
		return strSource.substring(iStart, iEnd);
	}
}
